package cn.ant.service.impl;

import cn.ant.entity.FlowRollbackParams;
import cn.ant.entity.FlowStartParams;
import cn.ant.entity.FlowTaskEntity;
import cn.ant.service.FlowManagerService;
import cn.ant.service.FlowTransactionalService;
import cn.ant.service.custom.CustomSimpleSerialUserTask;
import cn.ant.service.custom.CustomSubProcessParallelUserTask;
import cn.ant.service.custom.CustomSubProcessSerialUserTask;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.*;
import org.flowable.bpmn.model.Process;
import org.flowable.common.engine.api.query.QueryProperty;
import org.flowable.common.engine.impl.util.IoUtil;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.impl.dynamic.DynamicEmbeddedSubProcessBuilder;
import org.flowable.engine.impl.dynamic.DynamicSubProcessJoinInjectUtil;
import org.flowable.engine.impl.dynamic.DynamicUserTaskBuilder;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.DeploymentBuilder;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.repository.ProcessDefinitionQuery;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.image.impl.DefaultProcessDiagramGenerator;
import org.flowable.job.api.Job;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;

import java.io.InputStream;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;


@Service
@Slf4j
public class FlowManagerServiceImpl implements FlowManagerService {

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;


    @Autowired
    private HistoryService historyService;

    @Autowired
    private FlowTransactionalService flowTransactionalService;

    @Autowired
    private ManagementService managementService;

    @Autowired
    private DynamicBpmnService dynamicBpmnService;


    /**
     * 部署流程
     *
     * @param flowFileName
     * @return
     */
    @Override
    public String deployFlow(String flowFileName) {
        log.info("deployFlow.start  {}", flowFileName);
        DeploymentBuilder deploymentBuilder = repositoryService
                .createDeployment()
                .name(flowFileName)
                .addClasspathResource("process/" + flowFileName + ".bpmn20.xml");
        Deployment deploy = deploymentBuilder.deploy();
        log.info("deployFlow.end {}", deploy);
        //返回部署的流程部署Id
        return deploy.getId();
    }

    /**
     * 启动流程
     *
     * @param flowStartParams
     * @return
     */
    @Override
    public String startFlow(FlowStartParams flowStartParams) {
        log.info("startFlow.start {}", flowStartParams);
        flowStartParams.getData().put("startFlow time is {}", new Date().toLocaleString());
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(flowStartParams.getFlowDefinitionId(), flowStartParams.getData());
        log.info("startFlow.end {}", processInstance);
        //返回流程实例Id
        return processInstance.getId();
    }

    @Override
    public String completeTaskByTaskId(String taskId) {
        log.info("completeTaskByTaskId.start {}", taskId);
        taskService.complete(taskId);
        log.info("completeTaskByTaskId.end");
        return null;
    }

    @Override
    public void rollBackSingle(FlowRollbackParams flowRollbackParams) {
        runtimeService.createChangeActivityStateBuilder()
                .processInstanceId(flowRollbackParams.getFlowInstanceId())
                .moveActivityIdTo(flowRollbackParams.getFlowCurrentTaskDefinitionId(), flowRollbackParams.getFlowRollbackTaskDefinitionId())
                .changeState();
    }

    @Override
    public List<FlowTaskEntity> getRunningTaskList() {
        log.info("getRunningTaskList.start");
        List<Task> taskList = taskService.createTaskQuery().list();
        List<FlowTaskEntity> flowTaskEntityList = new ArrayList<>();
        for (int i = 0; i < taskList.size(); i++) {
            Task task = taskList.get(i);
            Execution execution = runtimeService.createExecutionQuery().executionId(task.getExecutionId()).singleResult();
            FlowTaskEntity flowTaskEntity = new FlowTaskEntity();
            flowTaskEntity.setSubInstanceId(execution.getParentId());
            flowTaskEntity.setInstanceId(task.getProcessInstanceId());
            flowTaskEntity.setTaskId(task.getId());
            flowTaskEntity.setTaskName(task.getName());
            flowTaskEntityList.add(flowTaskEntity);
        }
        log.info("getRunningTaskList.finish {}", taskList);
        return flowTaskEntityList;
    }

    @Autowired
    private TransactionTemplate transactionTemplate;

    @Override
    public void batchTaskByFlowId(List<String> processIds) {
        //创建一个单线程池
        ExecutorService threadExecutor = Executors.newSingleThreadExecutor();
        log.info("batchTaskByFlowId.start {}", processIds);
        List<Task> taskList = taskService.createTaskQuery().processInstanceIdIn(processIds).active().list();
        log.info("active list is {}", JSONUtil.parse(taskList));
        taskList.stream().forEach((task) -> {
            log.info("complete taskId is {}", task.getId());

            CompletableFuture.runAsync(() -> {
                transactionTemplate.execute(new TransactionCallback<Boolean>() {
                    @Override
                    public Boolean doInTransaction(TransactionStatus transactionStatus) {
                        try{
                            taskService.complete(task.getId());
                        }catch (Exception e){
                            transactionStatus.setRollbackOnly();
                            return false;
                        }
                        return null;
                    }
                });
            },threadExecutor).exceptionally((e) -> {
                e.printStackTrace();
                return null;
            });
        });
        log.info("batchTaskByFlowId.finish {}", taskList);
    }

    @Override
    public void batchJobByFlowId(List<String> processIds) {
        log.info("batchJobByFlowId.start");
        for (String processId : processIds) {
            List<Job> list = managementService.createJobQuery().processInstanceId(processId).list();
            log.info("batchJobByFlowId.list {}", list);
            for (Job job : list) {
                CompletableFuture.runAsync(() -> {
                    managementService.executeJob(job.getId());
                }).exceptionally((e) -> {
                    e.printStackTrace();
                    return null;
                });
            }
        }
        log.info("batchJobByFlowId.finish");
    }


    @Override
    public boolean isFinished(String processInstanceId) {
        return historyService.createHistoricProcessInstanceQuery().finished()
                .processInstanceId(processInstanceId).count() > 0;
    }


    public byte[] getFlowImage(String processInstanceId) throws Exception {
        //获取历史流程实例
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        //获取历史活动节点  按照id升序排序（即节点执行先后顺序）
//        List<HistoricActivityInstance> historicActivityInstanceList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).deleteReason("Change activity to rollback_one").orderByHistoricActivityInstanceId().asc().list();
        List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).orderByHistoricActivityInstanceId().asc().list();
        //获取当前活动节点
        List<Execution> executionList = runtimeService.createExecutionQuery().processInstanceId(processInstanceId).list();
//        //回滚过的节点
//        List<String> rollbackActivitis = new ArrayList<String>();
        //所有历史节点
        List<String> allActivitis = new ArrayList<>();
        //过滤之后的节点
        List<String> activitis = new ArrayList<>();
        //画布
        ProcessDiagramGenerator processDiagramGenerator = new DefaultProcessDiagramGenerator();

        //活动节点的id
        List<String> runningActivitisIdList = new ArrayList<>();
        for (Execution execution : executionList) {
            if (StrUtil.isNotBlank(execution.getActivityId())) {
                runningActivitisIdList.add(execution.getActivityId());
            }
        }

        //回滚过的节点
//        for (HistoricActivityInstance historicActivityInstance : historicActivityInstanceList) {
//            rollbackActivitis.add(historicActivityInstance.getActivityId());
//        }
//        List<String> rollbackActivitiList = rollbackActivitis.stream().distinct().collect(Collectors.toList());
        allActivitis = historicActivityInstances.stream().filter(x -> {
                    log.info("========>getDeleteReason {}", x.getDeleteReason());
                    return !"Change activity to rollback_one".equalsIgnoreCase(x.getDeleteReason());
                }
        ).map(HistoricActivityInstance::getActivityId).collect(Collectors.toList());
        log.info("allActivitis ==> {}", allActivitis);
        //获取流程图
        log.info("historicProcessInstance_getProcessDefinitionId {}", historicProcessInstance.getProcessDefinitionId());
        BpmnModel bpmnModel = repositoryService.getBpmnModel(historicProcessInstance.getProcessDefinitionId());

        InputStream in = new DefaultProcessDiagramGenerator().generateDiagram(bpmnModel, "png", allActivitis, runningActivitisIdList, "宋体", "宋体", "宋体", null, 1.0, false);
        byte[] buf = null;
        try {
            buf = IoUtil.readInputStream(in, "flow image name");
        } catch (Exception e) {
            log.error("操作异常", e);
        } finally {
            IoUtil.closeSilently(in);
        }
        return buf;

    }

    @Override
    public String addTask(String processInstanceId) {
        //动态创建一个用户任务
        DynamicUserTaskBuilder dynamicUserTaskBuilder = new DynamicUserTaskBuilder();
        dynamicUserTaskBuilder.assignee("做任务的人");
        String dynamicTaskId = UUID.randomUUID().toString().replace("-", "");
        dynamicUserTaskBuilder.setName("新增节点");
        dynamicUserTaskBuilder.setId("UserTaskAdd" + dynamicTaskId);
        List<Task> list = taskService.createTaskQuery().processInstanceId(processInstanceId).active().list();
        list.stream().forEach(task -> {
            String processDefinitionId = task.getProcessDefinitionId();
            log.info("getProcessDefinitionId ===> {}", processDefinitionId);
            BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
            log.info("bpmnModel=====> {}", bpmnModel);
            String taskDefinitionKey = task.getTaskDefinitionKey();
            log.info("getTaskDefinitionId ==> {}", taskDefinitionKey);
            FlowElement flowElement = bpmnModel.getFlowElement(taskDefinitionKey);
            log.info("flowElement.getName=====> {}", flowElement.getName());
            //拿到任务监听器的表达式
            log.info("UserTask info ===> {}", ((UserTask) flowElement).getTaskListeners().get(0).getImplementation());
            log.info("UserTask info ===> {}", ((UserTask) flowElement).getTaskListeners().get(0).getCustomPropertiesResolverImplementation());
            log.info("UserTask info ===> {}", ((UserTask) flowElement).getTaskListeners().get(0).getCustomPropertiesResolverImplementationType());
            log.info("UserTask info ===> {}", ((UserTask) flowElement).getTaskListeners().get(0).getImplementationType());
            log.info("UserTask info ===> {}", ((UserTask) flowElement).getTaskListeners().get(0).getInstance());
            log.info("UserTask info ===> {}", ((UserTask) flowElement).getTaskListeners().get(0).getOnTransaction());
            log.info("UserTask info ===> {}", ((UserTask) flowElement).getTaskListeners().get(0).getEvent());
            log.info("UserTask info ===> {}", ((UserTask) flowElement).getTaskListeners().get(0).getFieldExtensions().get(0).getStringValue());
            log.info("UserTask info ===> {}", ((UserTask) flowElement).getTaskListeners().get(0).getFieldExtensions().get(0).getFieldName());
            log.info("UserTask info ===> {}", ((UserTask) flowElement).getTaskListeners().get(0).getFieldExtensions().get(0).getExpression());
            log.info("UserTask info ===> {}", ((UserTask) flowElement).getTaskListeners().get(0).getAttributes());
            log.info("UserTask info ===> {}", ((UserTask) flowElement).getTaskListeners().get(0).getExtensionElements());
            //表达式参数
//            log.info("UserTask info ===> {}", ((UserTask) flowElement).getTaskListeners().get(0).getFieldExtensions());
//            CustomSimpleSerialUserTask cmdService = new CustomSimpleSerialUserTask(processInstanceId, flowElement, dynamicUserTaskBuilder);
//            managementService.executeCommand(cmdService);
//            new DynamicEmbeddedSubProcessBuilder()
        });

        return dynamicTaskId;
    }

    @Override
    public List<String> addSubTask(String processInstanceId) {
        List<String> strings = new ArrayList<>();
        //当前任务列表
        List<Task> list = taskService.createTaskQuery().processInstanceId(processInstanceId).active().list();
        for (Task task : list) {
            //生成任务Id
            String dynamicSubTaskId = UUID.randomUUID().toString().replace("-", "");
            strings.add(dynamicSubTaskId);
            //动态创建一个用户任务
            DynamicUserTaskBuilder dynamicUserTaskBuilder = new DynamicUserTaskBuilder();
            dynamicUserTaskBuilder.assignee("做任务的人");
            dynamicUserTaskBuilder.setName("新增节点");
            dynamicUserTaskBuilder.setId("dynamicSubTaskId" + dynamicSubTaskId);
            String definitionId = task.getProcessDefinitionId();
            log.info("getProcessDefinitionId ==> {}", definitionId);
            //获取当前状态模板
            BpmnModel bpmnModel = repositoryService.getBpmnModel(definitionId);
            List<Process> processes = bpmnModel.getProcesses();
            for (Process process : processes) {
                log.info("process_============> {}", process);
                for (String key : process.getFlowElementMap().keySet()) {
                    log.info("key_==================> {}", key);
                    FlowElement flowElement = process.getFlowElementMap().get(key);
                    log.info("flowElement_getName_=============> {}", flowElement.getName());
                    log.info("flowElement_getId_=============> {}", flowElement.getId());
                }
            }

            //获取当前节点
            String taskDefinitionKey = task.getTaskDefinitionKey();
            log.info("getProcessDefinitionId ==> {}", taskDefinitionKey);
            FlowElement flowElement = bpmnModel.getFlowElement(taskDefinitionKey);
            log.info("flowElement =======> {}", flowElement);
            //获取当前任务节点的子流程
            SubProcess subProcess = flowElement.getSubProcess();
            Collection<FlowElement> flowElements = subProcess.getFlowElements();
            log.info("subProcess ==========> {}", flowElements);
            for (FlowElement element : flowElements) {
                log.info("element =======> {}", element.getName());
            }
////            加入子任务
//            CustomSubProcessSerialUserTask customSubProcessSerialUserTask = new CustomSubProcessSerialUserTask(processInstanceId, subProcess, flowElement, dynamicUserTaskBuilder);
//            managementService.executeCommand(customSubProcessSerialUserTask);
            break;
        }

        return strings;
    }

    @Override
    public List<String> addSubTaskByProcessDefinition(String processInstanceId, String processDefinitionKey, String taskDefinitionKey) {
        log.info("addSubTaskByProcessDefinition.start");
        log.info("addSubTaskByProcessDefinition_start_param {}", taskDefinitionKey);
        //根据流程定义id，获取最新部署的流程进行修改
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey(processDefinitionKey)
                .latestVersion().singleResult();
        log.info("processDefinition_===========> {}", processDefinition);
        log.info("processDefinition_getId_===========> {}", processDefinition.getId());
        //根据ACT_RE_PROCDEF表的id，获取流程模板
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
        //获取主流程
        List<Process> processes = bpmnModel.getProcesses();
        log.info("processes_===>{}", processes);
        log.info("processes_size_===> {}", processes.size());
        for (Process process : processes) {
//            //获取主流程中的所有元素（不包括显示子流程中的元素，子流程的元素需要从子流程中获取）
//            Collection<FlowElement> flowElements = process.getFlowElements();
//            log.info("flowElements_============>{}",flowElements);
//            log.info("flowElements_size_===========> {}",flowElements.size());
//            for (FlowElement flowElement : flowElements) {
//                log.info("flowElement_=========> {}",flowElement);
//                log.info("flowElement_getId_=========> {}",flowElement.getId());
//                log.info("flowElement_getName_=========> {}",flowElement.getName());
//            }
            //获取主流程包括子流程中的所有元素
            Map<String, FlowElement> flowElementMap = process.getFlowElementMap();
            log.info("flowElementMap_size_===============> {}", flowElementMap.size());
            for (String key : flowElementMap.keySet()) {
                log.info("flowElementMap_key_======> {}", key);
                FlowElement flowElement = flowElementMap.get(key);
//                log.info("flowElement_================>{}", flowElement);
                log.info("flowElement_getId_================>{}", flowElement.getId());
                log.info("flowElement_getName_================>{}", flowElement.getName());
                if (taskDefinitionKey.equalsIgnoreCase(flowElement.getId())) {
                    //动态创建一个用户任务
                    DynamicUserTaskBuilder dynamicUserTaskBuilder = new DynamicUserTaskBuilder();
                    dynamicUserTaskBuilder.assignee("做任务的人");
                    dynamicUserTaskBuilder.setName("新增节点");
                    dynamicUserTaskBuilder.setId("newNodeId-" + new Random().nextInt(100000));
                    //获取这个任务的子流程
                    SubProcess subProcess = flowElement.getSubProcess();
                    //重新定制流程图
                    CustomSubProcessSerialUserTask customSubProcessSerialUserTask = new CustomSubProcessSerialUserTask(processInstanceId, subProcess, flowElement, dynamicUserTaskBuilder);
                    managementService.executeCommand(customSubProcessSerialUserTask);
                    break;
                }
            }
        }
        log.info("bpmnModel_==========> {}", bpmnModel);
        log.info("addSubTaskByProcessDefinition.end");
        return null;
    }

    @Override
    public void hangUp(String processInstanceId) {
        log.info("hangUp.start");
        runtimeService.suspendProcessInstanceById(processInstanceId);
        log.info("hangUp.end");
    }

    @Override
    public void activate(String processInstanceId) {
        log.info("hangUp.start");
        runtimeService.activateProcessInstanceById(processInstanceId);
        log.info("hangUp.end");
    }


}
